Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!: Rename --print flag to --output-scan #103

Merged
merged 1 commit into from
Sep 6, 2023

Conversation

viccuad
Copy link
Member

@viccuad viccuad commented Sep 1, 2023

Description

Relates to kubewarden/helm-charts#282.
Relates to #102.

Test

No need.

Additional Information

This signifies that using --output-scan can be consumed by end users.
I have checked the source code to ensure that the audit-scanner binary doesn't print to stdout or stderr in a way that isn't JSON formatted (unless it suddenly catches a panic and one gets an exception).
Also, the current config of golangci-lint forbids fmt.Println and the like.

This should provide reasonable certainty that stdout can be consumed by end users.

Tradeoff

Potential improvement

@viccuad viccuad requested a review from a team as a code owner September 1, 2023 16:01
@viccuad viccuad self-assigned this Sep 1, 2023
Copy link
Member

@flavio flavio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, I just left a minor comment

cmd/root.go Outdated
@@ -124,7 +124,7 @@ func init() {
rootCmd.Flags().StringP("kubewarden-namespace", "k", defaultKubewardenNamespace, "namespace where the Kubewarden components (e.g. PolicyServer) are installed (required)")
rootCmd.Flags().StringP("policy-server-url", "u", "", "URI to the PolicyServers the Audit Scanner will query. Example: https://localhost:3000. Useful for out-of-cluster debugging")
rootCmd.Flags().VarP(&level, "loglevel", "l", fmt.Sprintf("level of the logs. Supported values are: %v", logconfig.SupportedValues))
rootCmd.Flags().BoolVarP(&printJSON, "print", "p", false, "print result of scan in JSON to stdout")
rootCmd.Flags().BoolVarP(&printJSON, "output-scan", "o", false, "output result of scan to stdout in JSON upon completion")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpicking, can we use log-fmt like policy server does?

nnelas added a commit to nnelas/helm-charts that referenced this pull request Sep 6, 2023
- Removes customisation of the CA cert since this is generated by `kubewarden-controller` and there's no way to provide a custom one.
- Aligns `--print` flag with kubewarden/audit-scanner#103
@viccuad
Copy link
Member Author

viccuad commented Sep 6, 2023

Sorry for lagging on this PR.

Refactored, the behaviour now is as follows:

$ ./bin/audit-scanner  --help        
Scans resources in your kubernetes cluster with your already deployed Kubewarden policies.
Each namespace will have a PolicyReport with the outcome of the scan for resources within this namespace.
There will be a ClusterPolicyReport with results for cluster-wide resources.

Usage:
  audit-scanner [flags]

Flags:
  -c, --cluster                       scan cluster wide resources
  -f, --extra-ca string               File path to CA cert in PEM format of PolicyServer endpoints
  -h, --help                          help for audit-scanner
  -i, --ignore-namespaces strings     comma separated list of namespace names to be skipped from scan. This flag can be repeated
      --insecure-ssl                  skip SSL cert validation when connecting to PolicyServers endpoints. Useful for development
  -k, --kubewarden-namespace string   namespace where the Kubewarden components (e.g. PolicyServer) are installed (required) (default "kubewarden")
  -o, --log-fmt string                If set, print output result of scan to stdout in speficied format. Supported formats: [json]
  -l, --loglevel string               level of the logs. Supported values are: [trace debug info warn error fatal] (default "info")
  -n, --namespace string              namespace to be evaluated
  -u, --policy-server-url string      URI to the PolicyServers the Audit Scanner will query. Example: https://localhost:3000. Useful for out-of-cluster debugging

Passing incorrect --log-fmt:

$ ./bin/audit-scanner  --log-fmt=foo
{"level":"fatal","error":"passed log-fmt not supported. Please select one of the supported formats: [json]","time":"2023-09-06T13:18:48+02:00","message":"Error on cmd.Execute()"}

Passing correct --log-fmt=json gives us the end scan in the desired format:

$ ./bin/audit-scanner --log-fmt=json  -k kubewarden --namespace default --policy-server-url https://localhost:3000 -l debug --insecure-ssl
{"level":"info","time":"2023-09-06T13:18:59+02:00","message":"querying PolicyServers at https://localhost:3000 for debugging purposes. Don't forget to start `kwctl port-forward` if needed"}
{"level":"warn","time":"2023-09-06T13:18:59+02:00","message":"connecting to PolicyServers endpoints without validating TLS connection"}
{"level":"info","namespace":"default","time":"2023-09-06T13:18:59+02:00","message":"namespace scan started"}
{"level":"info","namespace":"default","dict":{"policies to evaluate":7,"policies skipped":0},"time":"2023-09-06T13:19:00+02:00","message":"policy count"}
{"level":"debug","dict":{"report name":"polr-ns-default","report ns":"default","report resourceVersion":"101152"},"time":"2023-09-06T13:19:00+02:00","message":"PolicyReport found"}
{"level":"debug","skip-evaluation":{"policy":"do-not-run-as-root","policyResourceVersion":"65533","policyUID":"0fa3a93d-30b3-4b8e-9332-720956c0d6c1","resource":"nginx-privileged","resourceResourceVersion":"101123"},"time":"2023-09-06T13:19:00+02:00","message":"Previous result found. Reusing result"}
{"level":"debug","skip-evaluation":{"policy":"do-not-share-host-paths","policyResourceVersion":"65546","policyUID":"8dff085b-1d92-4f2e-bbd6-7e0f11eae348","resource":"nginx-privileged","resourceResourceVersion":"101123"},"time":"2023-09-06T13:19:00+02:00","message":"Previous result found. Reusing result"}
{"level":"debug","skip-evaluation":{"policy":"drop-capabilities","policyResourceVersion":"65514","policyUID":"079179b9-f1e4-451d-a9f7-7e255b5c00c0","resource":"nginx-privileged","resourceResourceVersion":"101123"},"time":"2023-09-06T13:19:00+02:00","message":"Previous result found. Reusing result"}
{"level":"debug","skip-evaluation":{"policy":"no-host-namespace-sharing","policyResourceVersion":"65523","policyUID":"154cd0e9-6d59-48c2-97f5-580a6a8634ed","resource":"nginx-privileged","resourceResourceVersion":"101123"},"time":"2023-09-06T13:19:00+02:00","message":"Previous result found. Reusing result"}
{"level":"debug","skip-evaluation":{"policy":"no-privilege-escalation","policyResourceVersion":"65526","policyUID":"5ca390b5-7d51-4f54-86ea-7ca921b51851","resource":"nginx-privileged","resourceResourceVersion":"101123"},"time":"2023-09-06T13:19:00+02:00","message":"Previous result found. Reusing result"}
{"level":"debug","skip-evaluation":{"policy":"no-privileged-pod","policyResourceVersion":"65530","policyUID":"b4f7b09d-c7a5-4424-9929-c34a3446220f","resource":"nginx-privileged","resourceResourceVersion":"101123"},"time":"2023-09-06T13:19:00+02:00","message":"Previous result found. Reusing result"}
{"level":"debug","dict":{"report name":"polr-ns-default","report ns":"default","report resourceVersion":"101152"},"time":"2023-09-06T13:19:00+02:00","message":"PolicyReport found"}
{"level":"debug","dict":{"report name":"polr-ns-default","report ns":"default","report resourceVersion":"101152"},"time":"2023-09-06T13:19:00+02:00","message":"PolicyReport found"}
{"level":"info","dict":{"report name":"polr-ns-default","report ns":"default","report resourceVersion":"101152","summary":"{\"pass\":5,\"fail\":1,\"warn\":0,\"error\":0,\"skip\":0}"},"time":"2023-09-06T13:19:00+02:00","message":"updated PolicyReport"}
{"level":"info","namespace":"default","time":"2023-09-06T13:19:00+02:00","message":"namespace scan finished"}
{"cluster":{"metadata":{"name":"polr-clusterwide","uid":"abc12691-8395-459c-ad5b-9411bae2cb86","resourceVersion":"65555","generation":3,"creationTimestamp":"2023-09-01T08:39:11Z","labels":{"app.kubernetes.io/managed-by":"kubewarden"},"managedFields":[{"manager":"audit-scanner","operation":"Update","apiVersion":"wgpolicyk8s.io/v1alpha2","time":"2023-09-05T17:06:01Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:labels":{".":{},"f:app.kubernetes.io/managed-by":{}}},"f:results":{},"f:summary":{".":{},"f:error":{},"f:fail":{},"f:pass":{},"f:skip":{},"f:warn":{}}}}]},"summary":{"pass":6,"fail":1,"warn":0,"error":0,"skip":0},"results":[{"source":"kubewarden","policy":"cap-safe-labels","rule":"safe-labels","category":"Resource validation","severity":"low","timestamp":{"seconds":1693933561,"nanos":0},"result":"pass","scored":true,"resources":[{"kind":"Namespace","name":"cert-manager","uid":"6fa05d34-da6a-41be-9fd4-eb0cbb013842","apiVersion":"v1","resourceVersion":"290"}],"resourceSelector":{},"properties":{"policy-resource-version":"65520","policy-uid":"4d68903d-f0a7-4689-a2cf-ec63f277f986","validating":"true"}},{"source":"kubewarden","policy":"cap-safe-labels","rule":"safe-labels","category":"Resource validation","severity":"low","timestamp":{"seconds":1693933561,"nanos":0},"result":"pass","scored":true,"resources":[{"kind":"Namespace","name":"default","uid":"354f0f27-d4bd-49ff-8d4b-fd0544a40079","apiVersion":"v1","resourceVersion":"195"}],"resourceSelector":{},"properties":{"policy-resource-version":"65520","policy-uid":"4d68903d-f0a7-4689-a2cf-ec63f277f986","validating":"true"}},{"source":"kubewarden","policy":"cap-safe-labels","rule":"safe-labels","category":"Resource validation","severity":"low","timestamp":{"seconds":1693933561,"nanos":0},"result":"fail","scored":true,"resources":[{"kind":"Namespace","name":"demo2","uid":"c38342fe-91f8-4f1e-b1ee-4fd783ec6ee4","apiVersion":"v1","resourceVersion":"65308"}],"resourceSelector":{},"message":"The following labels are denied: cost-center","properties":{"policy-resource-version":"65520","policy-uid":"4d68903d-f0a7-4689-a2cf-ec63f277f986","validating":"true"}},{"source":"kubewarden","policy":"cap-safe-labels","rule":"safe-labels","category":"Resource validation","severity":"low","timestamp":{"seconds":1693933561,"nanos":0},"result":"pass","scored":true,"resources":[{"kind":"Namespace","name":"kube-node-lease","uid":"5d4c6ea8-6bef-4421-992b-72dd4d3080bc","apiVersion":"v1","resourceVersion":"43"}],"resourceSelector":{},"properties":{"policy-resource-version":"65520","policy-uid":"4d68903d-f0a7-4689-a2cf-ec63f277f986","validating":"true"}},{"source":"kubewarden","policy":"cap-safe-labels","rule":"safe-labels","category":"Resource validation","severity":"low","timestamp":{"seconds":1693933561,"nanos":0},"result":"pass","scored":true,"resources":[{"kind":"Namespace","name":"kube-public","uid":"03c68d14-43b6-4fdd-a993-1fdfd37d8226","apiVersion":"v1","resourceVersion":"38"}],"resourceSelector":{},"properties":{"policy-resource-version":"65520","policy-uid":"4d68903d-f0a7-4689-a2cf-ec63f277f986","validating":"true"}},{"source":"kubewarden","policy":"cap-safe-labels","rule":"safe-labels","category":"Resource validation","severity":"low","timestamp":{"seconds":1693933561,"nanos":0},"result":"pass","scored":true,"resources":[{"kind":"Namespace","name":"kube-system","uid":"a6834419-41d4-4070-b674-6a8cd41397e1","apiVersion":"v1","resourceVersion":"18"}],"resourceSelector":{},"properties":{"policy-resource-version":"65520","policy-uid":"4d68903d-f0a7-4689-a2cf-ec63f277f986","validating":"true"}},{"source":"kubewarden","policy":"cap-safe-labels","rule":"safe-labels","category":"Resource validation","severity":"low","timestamp":{"seconds":1693933561,"nanos":0},"result":"pass","scored":true,"resources":[{"kind":"Namespace","name":"kubewarden","uid":"7ad50fa3-9337-43ac-ab37-bdab174219b9","apiVersion":"v1","resourceVersion":"596"}],"resourceSelector":{},"properties":{"policy-resource-version":"65520","policy-uid":"4d68903d-f0a7-4689-a2cf-ec63f277f986","validating":"true"}}]},"namespaces":[{"kind":"PolicyReport","apiVersion":"wgpolicyk8s.io/v1alpha2","metadata":{"name":"polr-ns-default","namespace":"default","uid":"233ba029-a882-41f0-b03f-5d7f5c131521","resourceVersion":"101152","generation":8,"creationTimestamp":"2023-09-05T17:05:32Z","labels":{"app.kubernetes.io/managed-by":"kubewarden"},"managedFields":[{"manager":"audit-scanner","operation":"Update","apiVersion":"wgpolicyk8s.io/v1alpha2","time":"2023-09-06T10:26:01Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:labels":{".":{},"f:app.kubernetes.io/managed-by":{}}},"f:results":{},"f:scope":{".":{},"f:name":{},"f:resourceVersion":{},"f:uid":{}},"f:summary":{".":{},"f:error":{},"f:fail":{},"f:pass":{},"f:skip":{},"f:warn":{}}}}]},"scope":{"name":"default","uid":"354f0f27-d4bd-49ff-8d4b-fd0544a40079","resourceVersion":"195"},"summary":{"pass":5,"fail":1,"warn":0,"error":0,"skip":0},"results":[{"source":"kubewarden","policy":"cap-do-not-run-as-root","rule":"do-not-run-as-root","category":"PSP","severity":"info","timestamp":{"seconds":1693995961,"nanos":0},"result":"pass","scored":true,"resources":[{"kind":"Pod","namespace":"default","name":"nginx-privileged","uid":"4240a567-76cd-44b3-85de-41494b69556a","apiVersion":"v1","resourceVersion":"101123"}],"resourceSelector":{},"properties":{"mutating":"true","policy-resource-version":"65533","policy-uid":"0fa3a93d-30b3-4b8e-9332-720956c0d6c1"}},{"source":"kubewarden","policy":"cap-do-not-share-host-paths","rule":"do-not-share-host-paths","category":"PSP","severity":"info","timestamp":{"seconds":1693995961,"nanos":0},"result":"pass","scored":true,"resources":[{"kind":"Pod","namespace":"default","name":"nginx-privileged","uid":"4240a567-76cd-44b3-85de-41494b69556a","apiVersion":"v1","resourceVersion":"101123"}],"resourceSelector":{},"properties":{"policy-resource-version":"65546","policy-uid":"8dff085b-1d92-4f2e-bbd6-7e0f11eae348","validating":"true"}},{"source":"kubewarden","policy":"cap-drop-capabilities","rule":"drop-capabilities","category":"PSP","severity":"info","timestamp":{"seconds":1693995961,"nanos":0},"result":"pass","scored":true,"resources":[{"kind":"Pod","namespace":"default","name":"nginx-privileged","uid":"4240a567-76cd-44b3-85de-41494b69556a","apiVersion":"v1","resourceVersion":"101123"}],"resourceSelector":{},"properties":{"mutating":"true","policy-resource-version":"65514","policy-uid":"079179b9-f1e4-451d-a9f7-7e255b5c00c0"}},{"source":"kubewarden","policy":"cap-no-host-namespace-sharing","rule":"no-host-namespace-sharing","category":"PSP","severity":"info","timestamp":{"seconds":1693995961,"nanos":0},"result":"pass","scored":true,"resources":[{"kind":"Pod","namespace":"default","name":"nginx-privileged","uid":"4240a567-76cd-44b3-85de-41494b69556a","apiVersion":"v1","resourceVersion":"101123"}],"resourceSelector":{},"properties":{"policy-resource-version":"65523","policy-uid":"154cd0e9-6d59-48c2-97f5-580a6a8634ed","validating":"true"}},{"source":"kubewarden","policy":"cap-no-privilege-escalation","rule":"no-privilege-escalation","category":"PSP","severity":"info","timestamp":{"seconds":1693995961,"nanos":0},"result":"pass","scored":true,"resources":[{"kind":"Pod","namespace":"default","name":"nginx-privileged","uid":"4240a567-76cd-44b3-85de-41494b69556a","apiVersion":"v1","resourceVersion":"101123"}],"resourceSelector":{},"properties":{"mutating":"true","policy-resource-version":"65526","policy-uid":"5ca390b5-7d51-4f54-86ea-7ca921b51851"}},{"source":"kubewarden","policy":"cap-no-privileged-pod","rule":"no-privileged-pod","category":"PSP","severity":"info","timestamp":{"seconds":1693995961,"nanos":0},"result":"fail","scored":true,"resources":[{"kind":"Pod","namespace":"default","name":"nginx-privileged","uid":"4240a567-76cd-44b3-85de-41494b69556a","apiVersion":"v1","resourceVersion":"101123"}],"resourceSelector":{},"message":"Privileged container is not allowed","properties":{"policy-resource-version":"65530","policy-uid":"b4f7b09d-c7a5-4424-9929-c34a3446220f","validating":"true"}}]}]}

With Cobra, I couldn't find a sane way to allow for a --log-fmt without an argument, so passing --log-fmt would enable the scan output in json as default. I think it's better this way, as --log-fmt should be reused in the future for the format of the rest of the logs (not only the last line here with the scan output), once we support more formats.

@viccuad viccuad changed the title refactor!: Rename --print flag to --output-scan refactor!: Rename --print flag to --log-fmt, support json Sep 6, 2023
cmd/root.go Outdated
return err
}
switch logFormat {
// TODO use slices package in go 1.21
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can start to use it already. In the CA changes PR I've updated the go to 1.21 as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, let's move to Go 1.21

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done!

Copy link
Member

@flavio flavio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall good, I left some small comments

cmd/root.go Outdated
var logFormat string

// list of supported format of logs to stdout & stderr
var logFormatSupportedFormats = [1]string{"json"}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we have also a text format, which would be the current one?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but, the current one outputs a json per line (see the output on previous comment). Maybe I'm misunderstanding here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prior to this PR, the output was not JSON-encoded, am I right? It was something like

DATETIME - WARN - foo bar

This would be the default format to use, the text one.

To go back to policy-server, when no --log-fmt is not provided the log is in "human"/text mode. A different format can be picked by specifying --log-fmt <FMT>. This is how audit-scanner will work once this PR is merged. I just propose to add text as one of the possible values of log-fmt

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, the output was always JSON, for the logs from zerolog, or the scan output.

zerolog seems to only support JSON or a binary format. This would apply to normal logs.

For the scan result, I'm afraid that it can be quite verbose for logs, so IMHO it should be disabled by default. That's the current behaviour and the one from this PR.
Before this PR one needed to do --print to print the result of the scan in JSON.
With this PR, one needs to do --log-fmt=json to print the result of the scan in JSON. We could add other supported formats to the scan output, but to have the same output format for normal logs, we would need to refactor the use of zerolog of find an alternative.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I really misunderstood the whole thing. As discussed, let's go back to the original implementation (so --print), but with a better name of the flag (like --print-report). It would be a boolean flag, disabled by default. Once enabled it would print to the stdout the report using as a JSON object

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uook, no problem! Renamed from --print to --output-scan which was the first approach and matches kubewarden/helm-charts#282.

cmd/root.go Outdated
return err
}
switch logFormat {
// TODO use slices package in go 1.21
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, let's move to Go 1.21

@viccuad viccuad changed the title refactor!: Rename --print flag to --log-fmt, support json refactor!: Rename --print flag to --output-scan Sep 6, 2023
We consider this flag consumable by end users from now on.

Signed-off-by: Víctor Cuadrado Juan <[email protected]>
Copy link
Member

@flavio flavio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, sorry about the mess!

@viccuad viccuad merged commit efc01fe into kubewarden:main Sep 6, 2023
5 checks passed
flavio pushed a commit to kubewarden/helm-charts that referenced this pull request Sep 7, 2023
- Removes customisation of the CA cert since this is generated by `kubewarden-controller` and there's no way to provide a custom one.
- Aligns `--print` flag with kubewarden/audit-scanner#103
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

4 participants